package com.emerquim.bean.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;

import com.emerquim.bean.dao.ConexionJDBC;
import com.emerquim.persistence.dao.Caso;
import com.emerquim.persistence.dao.CasoDAO;
import com.emerquim.persistence.dao.SeguimientoPaciente;
import com.emerquim.security.AppUser;
import com.icesoft.faces.component.ext.HtmlInputHidden;
import com.icesoft.faces.context.effects.JavascriptContext;

/**
 * Clase para manejar los casos de un medico
 * @author Felipe Criales
 */
public class ManejadorCasosMedico {
	
	/**
	 * Funcionalidad de log
	 */
	private static final Logger log = Logger.getLogger(Evento.class);

	// ---------------------------------------------
	// Atributos
	// ---------------------------------------------
	/**
	 * La lista de casos activos para ese medico, dependiendo si estan abiertos o cerrados
	 */
	private List<Caso> casos;
	
	/**
	 * La lista de todos los casos para ese medico
	 */
	private List<Caso> allCasos;

	/**
	 * Parametro para indicar si se estan viendo los casos abiertos o cerrados
	 */
	private String casosAbiertos; 
	
	/**
	 * Atributo para manejar el paciente actual que al cual el doctor esta haciendo el seguimiento
	 */
	private Paciente paciente;
	
	/**
	 * Constructor sin parametros	
	 */
	public ManejadorCasosMedico() {
		this.casos = new ArrayList();
		this.allCasos = new ArrayList();
		this.casosAbiertos = "A";
		this.paciente = new Paciente();
	}

	/**
	 * Constructor de la clase
	 * @param casos
	 * @param casosAbiertos
	 * @author Felipe Criales
	 */
	public ManejadorCasosMedico(List<Caso> casos, String casosAbiertos) {
		super();
		this.casos = casos;
		this.casosAbiertos = casosAbiertos;
	}

	/**
	 * @return the casos
	 */
	public List<Caso> getCasos() {
		return casos;
	}
	
	/**
	 * Carga la lista de casos del medico
	 * @param event
	 * @author Felipe Criales
	 */
	public void cargarCasosMedico(ActionEvent event){
		CasoDAO casoDao = new CasoDAO();
		this.casosAbiertos = "A";
		try{	
			List<Caso> allCasos = casoDao.findAll();
			this.casos = new ArrayList();
			this.allCasos = new ArrayList();
			// Traer los casos de ese medico!!!
			FacesContext context = FacesContext.getCurrentInstance();
			AppUser appUser = (AppUser) context.getApplication().evaluateExpressionGet(context, "#{appUser}", AppUser.class);
			if(appUser != null){					
				if(appUser.getMedico() != null){
					java.util.Iterator<Caso> it = allCasos.iterator();
					while(it.hasNext()){
						Caso miCaso = (Caso) it.next();
						if(miCaso.getPTipoDocumentoByMedTdoId() != null && miCaso.getPMedicos() != null
								&& miCaso.getPMedicos().getId() != null){
							
							try {
								long tipoDocumento2 = appUser.getMedico().getId().getPTipoDocumento().getTdoId();
								long idMedico2 = appUser.getMedico().getId().getMedId();
								long tipoDocumento = miCaso.getPTipoDocumentoByMedTdoId().getTdoId();
								long idMedico = miCaso.getPMedicos().getId().getMedId();		
								if(idMedico == idMedico2 && tipoDocumento == tipoDocumento2){
									this.allCasos.add(miCaso);
									// Mirar el tipo de caso para llenar la lista normal de casos
									if(miCaso.getCasEstado().equals(this.casosAbiertos))
										this.casos.add(miCaso);									
								}
							} catch (Exception e) {
								log.error("Error al traer los datos de los casos para un medico.", e);
							}
						}
					}
				}
			}
		}catch  (HibernateException e) {			
			log.error("Error al guardar las agentes de un caso", e);
			throw e;
		}finally{
			casoDao.getSession().close();	 
		}
	}
	
	/**
	 * Metodo para el evento del cambio de un tipo de caso
	 * @param event El evento
	 * @author Felipe Criales
	 */
	public void cambioTipoCaso(ValueChangeEvent event) {
		String nuevoValor = (String) event.getNewValue();
		this.cambiarTipoCaso(nuevoValor);
	}
	
	/** 
	 * Metodo cuando se cambio el tipo del caso
	 * @author Felipe Criales
	 */
	public void cambiarTipoCaso(String nuevoValor){
		// 1. Limpiar el valor de los casos y el paciente actual
		this.casos.clear();
		this.paciente = new Paciente();				
		
		// 2. Recorrer todos los casos para traer los casos del tipo		
		Iterator<Caso> itAllCasos = this.allCasos.iterator();
		while(itAllCasos.hasNext()){
			try {
			Caso miCaso = (Caso) itAllCasos.next();
			miCaso.setSeleccionadoTabla(false);
			if(miCaso.getCasEstado().equals(nuevoValor))
				casos.add(miCaso);			
			} catch (Exception e) {
				log.error("Error al consultar los casos de un medico", e);
			}
		}
		
		// Trucaso para refrescar bien la vista del usuario
		JavascriptContext.addJavascriptCall(FacesContext.getCurrentInstance(),
			"document.location.reload();");
	}
	
	/**
	 * Metodo para trabajar con un caso en particular
	 * @param event El evento
	 * @author Felipe Criales
	 */
	public void trabajarCaso(ActionEvent event) {
		UIComponent component = (UIComponent)event.getComponent();
		HtmlInputHidden hiddenIdCaso = (HtmlInputHidden) component
			.findComponent("hiddenIdCaso");
		Long idCaso = (Long) hiddenIdCaso.getValue();	
		
		Iterator<Caso> it = this.casos.iterator();
		while(it.hasNext()){
			Caso casoCargar = (Caso) it.next();
			if(casoCargar.getCasId() == idCaso){
				this.paciente.inicializarDatosCaso(casoCargar);
				break;
			}			
		}
	}
	
	/**
	 * Carga la lista de casos del medico
	 * @param event
	 * @author Felipe Criales
	 */
	public void guardarCasoMedico(ActionEvent event){
		// 1. Cambiar el estado del caso dependiendo de la respuesta del usuario
		UIComponent component = (UIComponent)event.getComponent();
		HtmlInputHidden hiddenIdCaso = (HtmlInputHidden) component.findComponent("cerrarElCaso");
		String estadoCaso = (String) hiddenIdCaso.getValue();	
		this.paciente.setEstado(estadoCaso);
		this.guardarCasoBaseDatos();

		// 2. Recalcular los casos abiertos y cerrados del medico
		if(!this.casosAbiertos.equals(estadoCaso)){
			this.cargarCasosMedico(null);
			this.paciente = new Paciente();
		}
	}
	
	/**
	 * Metodo para guardar el caso en la base de datos y preguntar si quiere cerrar el caso
	 * @author Felipe Criales
	 */
	public void guardarCerrarCaso(){
		// 0. Solo se puede guardar el caso si se esta trabajando con uno
		if(this.paciente.getCaso() != null){			
			// 1. Pregutar cerrar el caso si el caso esta abierto
			if(this.paciente.getEstado().equals("A")){			
				String funcion = "preguntarCerrarCasoMedico();";
				JavascriptContext.addJavascriptCall(FacesContext.getCurrentInstance(), funcion);
			}
			// 2. En caso contrario solo guardar los datos del caso
			else{
				this.guardarCasoBaseDatos();
			}
		}
		else{
			String funcion = "alert('Debe escoger un caso para guardarlo');";
			JavascriptContext.addJavascriptCall(FacesContext.getCurrentInstance(), funcion);
		}
	}
	
	/**
	 * Metodo para guardar el caso actual del medico en la base de datos
	 */
	public boolean guardarCasoBaseDatos(){
		// 1. Guardar la informacion del caso
		Caso miCasoActual = this.paciente.getCaso();
		this.paciente.crearCasoDatosBasicos(miCasoActual, miCasoActual.getEvento());
		ConexionJDBC.executeQuery("DELETE FROM SEGUIMIENTO_PACIENTE WHERE CAS_ID = " + miCasoActual.getCasId());
		
		// 1.1 Guardar la informacion de los seguimientos del caso
		Iterator<Tratamiento> it = this.paciente.getTratamientos().iterator();
		CasoDAO casoDao = new CasoDAO(); 		
		try{
			Set seguimientos = new HashSet(0);			
			while(it.hasNext()){
				Tratamiento trata = it.next();
				SeguimientoPaciente seguimiento = new SeguimientoPaciente();
				seguimiento.setCaso(miCasoActual);
				seguimiento.setSepSintoma(trata.getSintomatologiaInicial());
				seguimiento.setSepTipexp(trata.getTipoExposicion());
				seguimiento.setSepFecha(trata.getFecha());
				java.sql.Time horaTrata = new java.sql.Time(trata.getFecha().getTime());
				seguimiento.setSepHora(horaTrata);								
				seguimiento.setSepClasificacion(trata.getClasificacionInicialEvento());
				seguimiento.setSepDescripcion(trata.getDescripcion());
				if(trata.isRequiereRemision())
					seguimiento.setSepRemision("S");
				else
					seguimiento.setSepRemision("N");
				seguimiento.setSepEtapa(trata.getEtapaTratamiento());
				seguimientos.add(seguimiento);
			}
			miCasoActual.setSeguimientos(seguimientos);
			casoDao.getSession().beginTransaction();			
			casoDao.update(miCasoActual);
			casoDao.getSession().getTransaction().commit();
		}catch  (HibernateException e) {			
			log.error("Error al guardar los datos de un caso", e);
			return false;
		}finally{
			casoDao.getSession().close(); 
		}		
		log.info("Se guardo el seguimiento exitosamente");
		return true;
	}

	/**
	 * @param casos the casos to set
	 */
	public void setCasos(List<Caso> casos) {
		this.casos = casos;
	}

	/**
	 * @return the casosAbiertos
	 */
	public String getCasosAbiertos() {
		return casosAbiertos;
	}

	/**
	 * @param casosAbiertos the casosAbiertos to set
	 */
	public void setCasosAbiertos(String casosAbiertos) {
		this.casosAbiertos = casosAbiertos;
	}

	/**
	 * @return the allCasos
	 */
	public List<Caso> getAllCasos() {
		return allCasos;
	}

	/**
	 * @param allCasos the allCasos to set
	 */
	public void setAllCasos(List<Caso> allCasos) {
		this.allCasos = allCasos;
	}

	/**
	 * @return the paciente
	 */
	public Paciente getPaciente() {
		return paciente;
	}

	/**
	 * @param paciente the paciente to set
	 */
	public void setPaciente(Paciente paciente) {
		this.paciente = paciente;
	}
}
